Skip to content

feat(subtitle): add ZapCap captions provider#128

Open
Najji wants to merge 2 commits into
calesthio:mainfrom
Najji:feat/zapcap-captions-provider
Open

feat(subtitle): add ZapCap captions provider#128
Najji wants to merge 2 commits into
calesthio:mainfrom
Najji:feat/zapcap-captions-provider

Conversation

@Najji

@Najji Najji commented Jun 22, 2026

Copy link
Copy Markdown

What

Adds ZapCap as a subtitle/captions provider so OpenMontage can burn animated, word-synced caption templates (Hormozi, Beast, Devin, ...) into a video via the ZapCap API.

Changes

  • tools/subtitle/zapcap_captions.py — new zapcap_captions BaseTool (capability=subtitle, provider=zapcap, runtime=API). Wraps the full flow — upload (local file or URL) → create task → poll → download — with a granular action dispatcher (list_templates, upload, create_task, get_task, approve_transcript, balance) for multi-template / multi-language fan-out via transcript_task_id + translate_to.
  • .agents/skills/zapcap-captions/SKILL.md — Layer 3 skill: flow, templates, renderOptions schema, translation/fan-out, failure modes.
  • Docsdocs/PROVIDERS.md provider section + env summary, AGENT_GUIDE.md Layer 3 table row, README.md subtitles row, .env.example key.

Subtitle capability goes from 2 → 3 providers (subtitle_gen, remotion_caption_burn, zapcap_captions).

Configuration

Single env var: ZAPCAP_API_KEY (requires a ZapCap Pro plan + API credits).

Verification

Verified end-to-end against api.zapcap.ai: free FFmpeg render → ZapCap caption (Hormozi 1 / Beast templates) → downloaded MP4. list_templates returns 29 templates; transcript came back accurate; output is a valid 1080×1920 MP4 with captions burned in.

Notes

  • .env and projects/ (verification artifacts) are gitignored and not included.

🤖 Generated with Claude Code

Add ZapCap as a subtitle/captions provider so OpenMontage can burn
animated, word-synced caption templates (Hormozi, Beast, Devin, ...)
into a video via the ZapCap API.

- tools/subtitle/zapcap_captions.py: new `zapcap_captions` BaseTool
  (capability=subtitle, provider=zapcap, runtime=API). Wraps the full
  flow — upload (local file or URL) -> create task -> poll -> download —
  with a granular `action` dispatcher (list_templates, upload,
  create_task, get_task, approve_transcript, balance) for multi-template
  / multi-language fan-out via transcript_task_id + translate_to.
  Auth via ZAPCAP_API_KEY; pinned to https://api.zapcap.ai.
- .agents/skills/zapcap-captions/SKILL.md: Layer 3 skill (flow,
  templates, renderOptions schema, translation/fan-out, failure modes).
- docs: PROVIDERS.md provider section + env summary, AGENT_GUIDE.md
  Layer 3 table row, README.md subtitles row, .env.example key.

Subtitle capability is now 3 providers (subtitle_gen, remotion_caption_burn,
zapcap_captions). Verified end-to-end against api.zapcap.ai: free FFmpeg
render -> ZapCap caption -> downloaded MP4, transcript accurate.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Najji
Najji marked this pull request as ready for review June 22, 2026 01:05
@Najji
Najji requested a review from calesthio as a code owner June 22, 2026 01:05

@rajpratham1 rajpratham1 left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a substantial but well-structured feature addition that integrates ZapCap as a new subtitle provider across the project. The implementation is comprehensive—it includes the provider implementation, documentation, configuration, agent skills, and environment setup, making it straightforward for users to adopt. The separation between the provider logic and the existing subtitle tools is also clearly documented, and the granular API actions (upload, create_task, get_task, etc.) provide good flexibility for more advanced workflows.

Repository owner deleted a comment from Anil-matcha Jun 24, 2026

@calesthio calesthio left a comment

Copy link
Copy Markdown
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thank you for the contribution. ZapCap is a real value-add for OpenMontage: styled, animated, word-synced social captions are materially different from plain SRT generation or local subtitle burn-in, and the tool has the right high-level shape: provider metadata, fallback tools, Layer 3 skill linkage, setup docs, and unavailable status when ZAPCAP_API_KEY is missing.

I need to request changes before merge because this adds a new 559-line paid/network provider without focused offline contract tests. Per docs/PR_REVIEW_GUIDE.md, provider additions should have at least contract/metadata, registry discovery, and status behavior coverage, with mocked API tests preferred over live-provider tests. This PR currently has no tests/ coverage for zapcap_captions.

Verification I ran:

python -m py_compile tools/subtitle/zapcap_captions.py
# passed

python -c "from tools.subtitle.zapcap_captions import ZapCapCaptions; from tools.tool_registry import registry; registry.discover(); print([t.name for t in registry.get_by_capability('subtitle')]); print(ZapCapCaptions().get_status())"
# ['subtitle_gen', 'zapcap_captions', 'remotion_caption_burn']
# ToolStatus.UNAVAILABLE

Please add focused mocked tests covering at minimum:

  • registry discovery under capability='subtitle'
  • get_status() with no key, missing requests, and configured key
  • local missing-file failure for input_path
  • template-name resolution / not-found behavior
  • mocked happy path for upload -> create_task -> poll -> download, including artifact/output data
  • one mocked API error path that verifies useful error reporting without leaking secrets

I did not find an actionable security issue in the reviewed diff, but the lack of provider tests is too much merge risk for this class of tool.

Address PR review: add focused mocked tests for the new paid/network
provider. All network I/O is stubbed at the tool's _request/_download
boundary — no live api.zapcap.ai calls, no API key required.

Covers:
- registry discovery under capability="subtitle" + contract metadata
- get_status(): no key / missing requests / configured key
- local missing-file failure for input_path (and asserts no network call)
- template-name resolution (case-insensitive) + not-found lists options
- mocked happy path: upload -> create_task -> poll -> download,
  asserting videoId/taskId/templateId/output/artifacts and the full
  request lifecycle (>=2 polls)
- mocked API error path: actionable error, API key never leaked
- task status=failed surfaces the upstream error

13 tests, all passing (python -m pytest tests/tools/test_zapcap_captions.py).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
@Najji

Najji commented Jul 7, 2026

Copy link
Copy Markdown
Author

Thanks for the review — added focused offline contract tests in tests/tools/test_zapcap_captions.py (commit aca9d91). All network I/O is stubbed at the tool's _request / _download boundary, so the suite makes no live api.zapcap.ai calls and needs no API key. 13 passed in 0.31s.

Mapping to the requested coverage:

Requested Test
registry discovery under capability='subtitle' test_registry_discovers_zapcap_under_subtitle (also asserts capability/provider/runtime + env:ZAPCAP_API_KEY dependency + skill linkage)
get_status() — no key test_status_unavailable_without_key
get_status() — missing requests test_status_unavailable_when_requests_missing
get_status() — configured key test_status_available_with_key_and_requests
local missing-file failure for input_path test_caption_missing_input_file_fails_cleanly (also asserts no network call is made for a missing local file)
template-name resolution / not-found test_resolve_template_id_by_name_case_insensitive, ..._unknown_name_raises_with_options, ..._requires_id_or_name
mocked happy path upload → create_task → poll → download, incl. artifact/output data test_caption_happy_path (asserts videoId/taskId/templateId/status/output, artifacts, downloaded file contents, and that ≥2 status polls ran)
mocked API error path, no secret leak test_caption_api_error_is_reported_without_leaking_key (asserts the error is actionable and the API key never appears in it)

Extra: test_task_failed_status_surfaces_error covers an upstream status: failed propagating its error, and test_base_url_is_production pins the endpoint.

@Najji
Najji requested a review from calesthio July 7, 2026 10:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants